<script lang='ts' setup>
import { onMounted, reactive, watch } from 'vue'
import { toCanvas } from 'qrcode'
import { get_settings, Settings } from '@/apis/setting/get_settings.ts'
import { set_auth } from '@/apis/setting/set_auth.ts'
import { set_smtp } from '@/apis/setting/set_smtp.ts'
import { Api } from '@/apis/structs.ts'

declare type State = {
  loading: boolean,
  auth: { type: string, password: string, repassword: string, email: string, secret: string, code: string },
  secret: { secret: string, content: string },
  smtp: { host: string, port: number, username: string, password: string, from: string },
  auth_saving: boolean,
  smtp_saving: boolean,
}

const state = reactive<State>({
  loading: true,
  auth: { type: 'fixed', password: '', repassword: '', email: '', secret: '', code: '' },
  secret: { secret: '', content: '' },
  smtp: { host: '', port: 25, username: '', password: '', from: '' },
  auth_saving: false,
  smtp_saving: false
})
watch(state, async function(_, n) {
  if ('totp' === n.auth.type) {
    setTimeout(async () => {
      await toCanvas(document.getElementById('auth-qr-code'), state.secret.content, { errorCorrectionLevel: 'H', width: 300 })
    }, 100)
  }
})

onMounted(async () => {
  get_settings().then(async (response: Api<Settings>) => {
    state.loading = false

    if (0 !== response.code) {
      window.$message.error(response.message)

      return
    }

    state.auth.type = response.data.auth.type
    state.auth.email = response.data.auth.email
    state.auth.secret = response.data.secret.secret
    state.smtp = response.data.smtp
    state.secret = response.data.secret
  })
})

async function save_auth(): Promise<void> {
  if (-1 === ['fixed', 'email-code', 'totp'].indexOf(state.auth.type)) {
    window.$message.error('无效的身份验证方式')

    return
  }

  if ('fixed' === state.auth.type && (6 > state.auth.password.trim().length || 32 < state.auth.password.trim().length || state.auth.password.trim() !== state.auth.repassword.trim())) {
    window.$message.error('验证密码无效，密码必须为6-32位长度，且重复密码必须与验证密码一致')

    return
  }

  if ('email-code' === state.auth.type && '' === state.auth.email.trim()) {
    window.$message.error('邮件地址不能为空')

    return
  }

  if ('totp' === state.auth.type && 6 !== state.auth.code.length) {
    window.$message.error('请输入6位数字的TOTP验证码')

    return
  }

  state.auth_saving = true
  const response = await set_auth(state.auth.type.trim(), state.auth.password.trim(), state.auth.email.trim(), state.auth.secret.trim(), state.auth.code.trim())
  state.auth_saving = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('保存成功，将在下次登录时生效')
}

async function save_smtp(): Promise<void> {
  if ('' === state.smtp.host.trim() || 0 > state.smtp.port || 65535 < state.smtp.port) {
    window.$message.error('SMTP服务器的域名与端口无效，请检查输入项')

    return
  }

  if ('' === state.smtp.username.trim() && '' != state.smtp.password.trim()) {
    window.$message.error('SMTP验证密码不为空时验证用户名不能为空')

    return
  }

  if ('' === state.smtp.from.trim()) {
    window.$message.error('发件人邮件地址不能为空')

    return
  }

  state.smtp_saving = true
  const response = await set_smtp(state.smtp.host.trim(), state.smtp.port, state.smtp.username.trim(), state.smtp.password.trim(), state.smtp.from.trim())
  state.smtp_saving = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('保存成功')
}
</script>

<template>
  <div class='content-wrap' style='width: 800px; margin: auto'>
    <n-space vertical>
      <n-divider>身份验证配置</n-divider>
      <template v-if='state.loading'>
        <n-skeleton height='25px' width='100%' />
      </template>
      <template v-else>
        <div>
          <n-space align='center'>
            <n-text>身份验证类型</n-text>
            <n-radio-group v-model:value='state.auth.type' name='auth-type'>
              <n-radio size='small' value='fixed'>固定密码</n-radio>
              <n-radio size='small' value='email-code'>邮件验证码</n-radio>
              <n-radio size='small' value='totp'>TOTP验证码</n-radio>
            </n-radio-group>
          </n-space>
        </div>
        <div v-if='"fixed" === state.auth.type'>
          <n-space vertical>
            <n-input-group>
              <n-input-group-label size='small'>固定密码</n-input-group-label>
              <n-input v-model:value='state.auth.password' placeholder='输入新的验证密码' size='small' type='password'></n-input>
            </n-input-group>
            <n-input-group>
              <n-input-group-label size='small'>确认密码</n-input-group-label>
              <n-input v-model:value='state.auth.repassword' placeholder='再次输入验证密码' size='small' type='password'></n-input>
            </n-input-group>
          </n-space>
        </div>
        <div v-if='"email-code" === state.auth.type'>
          <n-input-group>
            <n-input-group-label size='small'>邮件地址</n-input-group-label>
            <n-input v-model:value='state.auth.email' placeholder='输入用于接收验证码的邮件地址' size='small'></n-input>
          </n-input-group>
        </div>
        <div v-if='"totp" === state.auth.type'>
          <div>
            <n-input-group>
              <n-input-group-label size='small'>验证码</n-input-group-label>
              <n-input v-model:value='state.auth.code' placeholder='请使用身份验证器扫描下方二维码获取验证码，若二维码未显示请刷新页面重试' size='small'></n-input>
            </n-input-group>
          </div>
        </div>
        <div>
          <n-button :loading='state.auth_saving' class='width-max' size='small' type='primary' @click='save_auth'>保存</n-button>
        </div>
        <div v-if='"totp" === state.auth.type'>
          <n-space align='center' justify='center'>
            <div style='width: 300px;height: 300px;'>
              <canvas id='auth-qr-code' />
            </div>
          </n-space>
        </div>
      </template>
      <n-divider>SMTP服务器配置</n-divider>
      <template v-if='state.loading'>
        <n-skeleton height='25px' width='100%' />
        <n-skeleton height='25px' width='100%' />
        <n-skeleton height='25px' width='100%' />
      </template>
      <template v-else>
        <div>
          <n-space :wrap-item='false'>
            <div class='flex-max'>
              <n-input-group>
                <n-input-group-label size='small'>服务器域名</n-input-group-label>
                <n-input v-model:value='state.smtp.host' placeholder='输入服务器的域名地址' size='small'></n-input>
              </n-input-group>
            </div>
            <div>
              <n-input-group>
                <n-input-group-label size='small'>端口</n-input-group-label>
                <n-input-number v-model:value='state.smtp.port' max='65535' min='1' placeholder='端口' size='small'></n-input-number>
              </n-input-group>
            </div>
          </n-space>
        </div>
        <div>
          <n-space :wrap-item='false'>
            <div class='flex-max'>
              <n-input-group>
                <n-input-group-label size='small'>验证用户名</n-input-group-label>
                <n-input v-model:value='state.smtp.username' placeholder='输入服务器的验证用户名，可以为空' size='small'></n-input>
              </n-input-group>
            </div>
            <div class='flex-max'>
              <n-input-group>
                <n-input-group-label size='small'>验证密码</n-input-group-label>
                <n-input v-model:value='state.smtp.password' placeholder='输入服务器的验证密码' show-password-on='mousedown' size='small' type='password'></n-input>
              </n-input-group>
            </div>
          </n-space>
        </div>
        <div>
          <n-input-group>
            <n-input-group-label size='small'>发件人邮件地址</n-input-group-label>
            <n-input v-model:value='state.smtp.from' placeholder='输入发件人的邮件地址' size='small'></n-input>
          </n-input-group>
        </div>
        <div>
          <n-button :loading='state.smtp_saving' class='width-max' size='small' type='primary' @click='save_smtp'>保存</n-button>
        </div>
      </template>
    </n-space>
  </div>
</template>

<style scoped>

</style>
